//-
// ==========================================================================
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related 
// material (collectively the "Data") in these files contain unpublished 
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
// licensors, which is protected by U.S. and Canadian federal copyright 
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right 
// to use, modify, and incorporate this Data into other products for 
// purposes authorized by the Autodesk software license agreement, 
// without fee.
//
// The copyright notices in the Software and this entire statement, 
// including the above license grant, this restriction and the 
// following disclaimer, must be included in all copies of the 
// Software, in whole or in part, and all derivative works of 
// the Software, unless such copies or derivative works are solely 
// in the form of machine-executable object code generated by a 
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

/* 

	file : userMsgCmd.cpp
	class: userMessage
	----------------------
	This is an example to demonstrate the usages of the MUserEventMessage class.
	It allows the user to create, destroy, and post to user-defined events
	identified by strings.

	The command "userMessage" supports the following options:

		-r/-register string : Register a new event type with the given name.
			Registration also attaches two callback functions to the event,
			userCallback1 and userCallback2.

		-d/-deregister string : Deregister an existing event with the given name

		-p/-post string : Post the event.  In this case, it simply notifies
			userCallback1 and userCallback2, which print info messages.

		-t/-test : Run a basic set of tests that demonstrate how the user event
			types can be used.  See userMessage::runTests()

	Only one option should be specified per invokation.
	
*/

#include <maya/MFnPlugin.h>
#include <maya/MStatus.h>
#include <maya/MPxCommand.h>
#include <maya/MMessage.h>
#include <maya/MUserEventMessage.h>
#include <maya/MGlobal.h>
#include <maya/MArgList.h>
#include <maya/MArgDatabase.h>
#include <maya/MSyntax.h>

// Syntax string definitions
static const char *postFlag = "-p";
static const char *postLongFlag = "-post";
static const char *registerFlag = "-r";
static const char *registerLongFlag = "-register";
static const char *deregisterFlag = "-d";
static const char *deregisterLongFlag = "-deregister";
static const char *testFlag = "-t";
static const char *testLongFlag = "-test";

class userMessage : public MPxCommand
{
	public:
		virtual MStatus doIt( const MArgList& );
		void runTests();

		static void *creator();
		static MSyntax newSyntax();

		// callback functions.
		static void userCallback1(void* clientData);
		static void userCallback2(void* clientData);

	private:
		static MString stringClientData;
};

// Define a string that will be passed to the callback functions
MString userMessage::stringClientData = "Sample Client Data (an MString object)";

MStatus userMessage::doIt( const MArgList& args )
{
	MStatus status = MS::kSuccess;

	MArgDatabase argData(syntax(), args);

	if (argData.isFlagSet(deregisterFlag))
	{
		MString event;
		argData.getFlagArgument(deregisterFlag, 0, event);
		status = MUserEventMessage::deregisterUserEvent(event);
	}
	else if (argData.isFlagSet(registerFlag))
	{
		// Register the new event and add two fixed callbacks to it.
		MString event;
		argData.getFlagArgument(registerFlag, 0, event);
		if (!MUserEventMessage::isUserEvent(event)) {
			status = MUserEventMessage::registerUserEvent(event);
			if (status == MS::kSuccess)
			{
				MUserEventMessage::addUserEventCallback(event,userCallback1,(void*) &stringClientData,&status);
				MUserEventMessage::addUserEventCallback(event,userCallback2,(void*) &stringClientData,&status);
			}
		}
	}
	else if (argData.isFlagSet(postFlag))
	{
		MString event;
	 	argData.getFlagArgument(postFlag, 0, event);
		status = MUserEventMessage::postUserEvent(event);
	}
	else if (argData.isFlagSet(testFlag))
	{
		runTests();
	}

	return status;
}


void* userMessage::creator() 
{	
	return new userMessage;
}

MSyntax userMessage::newSyntax() {
	MSyntax syntax;
	syntax.addFlag( postFlag, postLongFlag, MSyntax::kString );
	syntax.addFlag( registerFlag, registerLongFlag, MSyntax::kString );
	syntax.addFlag( deregisterFlag, deregisterLongFlag, MSyntax::kString );
	syntax.addFlag( testFlag, testLongFlag );
	return syntax;
}

void userMessage::userCallback1(void* clientData) {
	MGlobal::displayInfo("Entered userMessage::userCallback1");
	if (clientData != 0)
	{
		MString receivedDataMsg(MString("Received data: ") + *((MString*) clientData));
		MGlobal::displayInfo(receivedDataMsg);
	}
}

void userMessage::userCallback2(void* clientData) {
	MGlobal::displayInfo("Entered userMessage::userCallback2");
	if (clientData != 0)
	{
		MString receivedDataMsg(MString("Received data: ") + *((MString*) clientData));
		MGlobal::displayInfo(receivedDataMsg);
	}
}

void userMessage::runTests() {

	MStatus status;

	// Test 1: Try to register callback for nonexistent event

	MGlobal::displayInfo("Starting Test 1");

	MUserEventMessage::addUserEventCallback("TestEvent",userCallback1,0,&status);
	if (!status) {
		MGlobal::displayInfo("Test 1 passed");
	}
	else {
		MGlobal::displayInfo("Test 1 failed");
	}

	// Test 2: Register and deregister an event 
	// - Expected output: Entered userMessage::userCallback1

	MGlobal::displayInfo("Starting Test 2");

	MUserEventMessage::registerUserEvent("TestEvent");
	MUserEventMessage::addUserEventCallback("TestEvent",userCallback1,0,&status);
	MUserEventMessage::postUserEvent("TestEvent");
	MUserEventMessage::deregisterUserEvent("TestEvent");

	// Test 3: The event should be gone
	MGlobal::displayInfo("Starting Test 3");
	MUserEventMessage::addUserEventCallback("TestEvent",userCallback1,0,&status);
	if (!status) {
		MGlobal::displayInfo("Test 3 passed");
	}
	else {
		MGlobal::displayInfo("Test 3 failed");
	}

	// Test 4: Try adding multiple callbacks to an event
	// Expected output: Entered userMessage::userCallback1
	//					Entered userMessage::userCallback2

	MGlobal::displayInfo("Starting Test 4");

	MUserEventMessage::registerUserEvent("TestEvent");
	MUserEventMessage::addUserEventCallback("TestEvent",userCallback1,0,&status);
	MUserEventMessage::addUserEventCallback("TestEvent",userCallback2,0,&status);
	MUserEventMessage::postUserEvent("TestEvent");
	MUserEventMessage::deregisterUserEvent("TestEvent");
   
	// Test 5: Try adding and posting to multiple events
	// Expected output: Posting first event
	//					Entered userMessage::userCallback1
	//					Entered userMessage::userCallback2
	//					Posting second event
	//					Entered userMessage::userCallback1
	//					Entered userMessage::userCallback2

	MGlobal::displayInfo("Starting Test 5");

	MUserEventMessage::registerUserEvent("TestEvent");
	MUserEventMessage::registerUserEvent("TestEvent2");
	MUserEventMessage::addUserEventCallback("TestEvent",userCallback1,0,&status);
	MUserEventMessage::addUserEventCallback("TestEvent",userCallback2,0,&status);
	MUserEventMessage::addUserEventCallback("TestEvent2",userCallback1,0,&status);
	MUserEventMessage::addUserEventCallback("TestEvent2",userCallback2,0,&status);
	MGlobal::displayInfo("Posting first event");
	MUserEventMessage::postUserEvent("TestEvent");
	MGlobal::displayInfo("Posting second event");
	MUserEventMessage::postUserEvent("TestEvent2");
	MUserEventMessage::deregisterUserEvent("TestEvent");
	MUserEventMessage::deregisterUserEvent("TestEvent2");
 
	MGlobal::displayInfo("Completed all tests");
}


// standard initialize and uninitialize functions

MStatus initializePlugin(MObject obj)
{
	// Version number may need to change in the future
	//
	MFnPlugin pluginFn(obj, PLUGIN_COMPANY, "6.0");

	MStatus status;
	status = pluginFn.registerCommand("userMessage", userMessage::creator, userMessage::newSyntax);

	if( !status)
		status.perror("register Command failed");

	return status;
}


MStatus uninitializePlugin ( MObject obj )
{
	MFnPlugin pluginFn(obj);
	MStatus status = MS::kSuccess;
	
	//remove call backs
	MUserEventMessage::deregisterUserEvent("TestFoo1");
	MUserEventMessage::deregisterUserEvent("TestFoo2");

	status = pluginFn.deregisterCommand("userMessage");
	
	return status;
}

